package com.polaris.live.floating

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import com.blankj.utilcode.util.NetworkUtils
import com.polaris.live.cache.CommonCache
import com.polaris.live.common.cacha.CacheUtil
import com.polaris.live.common.cacha.UserManager
import com.polaris.live.common.constant.CommonConst
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.manager.withRetryNow
import com.polaris.live.common.mvvm.activity.BaseVmActivity
import com.polaris.live.common.mvvm.base2.BaseVbActivity
import com.polaris.live.common.network.HTTP_SUCCESS_CODE
import com.polaris.live.common.network.request
import com.polaris.live.common.network.state.ResultState
import com.polaris.live.common.util.JsonUtils
import com.polaris.live.common.util.ToastGravity
import com.polaris.live.common.util.ViewUtils
import com.polaris.live.constant.LiveConst
import com.polaris.live.im.manager.ImLiveManager
import com.polaris.live.im.sfs.COMMAND_LIVE_JOIN
import com.polaris.live.im.sfs.COMMAND_LIVE_QUIT
import com.polaris.live.im.sfs.COMMAND_LIVE_RECOVER
import com.polaris.live.im.sfs.LIVE_KICK_ROOM
import com.polaris.live.im.sfs.LIVE_MAGIC_LAMP_OPEN
import com.polaris.live.im.sfs.bean.event.ImConnectedEvent
import com.polaris.live.im.sfs.bean.event.ImDisconnectedEvent
import com.polaris.live.im.sfs.bean.live.LiveJoinMessage
import com.polaris.live.im.sfs.bean.live.LiveMsgIdMessage
import com.polaris.live.im.sfs.bean.live.LiveQuitMessage
import com.polaris.live.im.sfs.bean.live.LiveRoomInfo
import com.polaris.live.im.sfs.bean.live.SendLiveCloseMessage
import com.polaris.live.im.sfs.bean.live.SendLiveFloatingMessage
import com.polaris.live.im.sfs.bean.live.SendLiveMessage
import com.polaris.live.im.sfs.bean.live.ext.UserBasicVo
import com.polaris.live.im.sfs.core.SmartFoxConnector
import com.polaris.live.im.sfs.core.SmartFoxManager
import com.polaris.live.im.sfs.core.SmartFoxQueueManager
import com.polaris.live.im.sfs.core.bean.DataArgument
import com.polaris.live.manager.LiveStateManager
import com.polaris.live.net.liveService
import com.polaris.live.net.payerService
import com.polaris.live.resp.back_resp.ScreenshotStrategyVo
import com.polaris.live.resp.bean.MagicLampCountDownBean
import com.polaris.live.resp.go_resp.LiveIdBean
import com.polaris.live.translation.R
import com.polaris.live.ui.live.bean.LiveInitInfo
import com.polaris.live.ui.live.widget.AbstractLiveMessageView
import com.polaris.live.ui.party.PartyUserStateUtil
import com.polaris.live.ui.party.listener.PartyImListener
import com.polaris.live.ui.party.utils.PartyImProxy
import com.polaris.live.ui.party.widget.seat.PartyStreamProxy
import com.polaris.live.ui.party.widget.seat.SeatBeanUtil
import com.polaris.live.ui.party.widget.seat.bean.SeatBean
import com.polaris.live.utils.LiveUtils
import com.polaris.live.utils.StartLiveProxy
import com.polaris.live.utils.parseLiveInfo
import com.polaris.live.utils.route.RoutePath
import com.polaris.live.utils.route.Router
import com.polaris.live.utils.zego.media.MediaProxy
import com.polaris.live.widget.gift.LiveMagicLampCountdownView.Companion.ANIMATION_MAX_TIME
import kotlinx.coroutines.Job
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import sfs2x.client.entities.variables.RoomVariable
import java.util.concurrent.ConcurrentLinkedQueue

/**
 * FloatingService
 *
 * @author Created by 天晴 on 2024/11/21 9:39
 * @since 1.0.0
 **/
class FloatingService(
    private val mIsAnchor: Boolean, //是不是主播
    private val mLiveInfo: LiveRoomInfo,  ///房间信息
    private val mPartyStreamProxy: PartyStreamProxy, //推拉流管理
    private val mSeatList: List<SeatBean>, //座位信息
    private val mMessageList: MutableList<SendLiveMessage>, //消息历史
    private val mScreenshotStrategy: ScreenshotStrategyVo? = null, //截图规则
    private val mPassword: String? = null, //房间密码
) : PartyImListener, LifecycleOwner, NetworkUtils.OnNetworkStatusChangedListener {

    private val mLifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this)

    private var mLastUserCount: Int = 0  //最后人数

    private var mIsDestroyed = false

    /**
     * Im消息控制
     */
    private var mPartyImProxy: PartyImProxy? = null

    //开奖等待
    private val mWaitingList = ConcurrentLinkedQueue<MagicLampCountDownBean>()
    private var nowMagicLampCountDownBean: MagicLampCountDownBean? = null //当前在执行的神灯
    private var magicJob: Job? = null

    init {
        // 设置初始状态
        setCurrentState(Lifecycle.State.INITIALIZED)
        setCurrentState(Lifecycle.State.CREATED)
        setCurrentState(Lifecycle.State.STARTED)
        initListener()
        launchLiveHeartbeat(mLiveInfo.liveId)
        //监听网络状态
        NetworkUtils.registerNetworkStatusChangedListener(this)
        EventBus.getDefault().register(this)
    }

    private fun initListener() {
        if (mPartyImProxy == null) {
            mPartyImProxy = PartyImProxy.create(
                mLiveInfo.liveId,
                mLiveInfo.userId,
                this,
                this
            )
        }
    }

    /**
     * 设置生命周期状态
     */
    private fun setCurrentState(state: Lifecycle.State) {
        mLifecycleRegistry.currentState = state
    }

    fun getRoomCover(): String? {
        return mLiveInfo.roomCover
    }

    fun getLiveRoomInfo(): LiveRoomInfo {
        return mLiveInfo
    }

    /**
     * =============================Im消息==============================
     */
    override fun closeRoomMessage(da: SendLiveCloseMessage) {

        FloatingWindowManager.onDestroyed(mLiveInfo.type, mLiveInfo.roomId)
    }

    override fun variableUpdate(variable: RoomVariable) {
        val liveInfo = mLiveInfo
        LiveUtils.fillLiveInfo(liveInfo, variable)
        SeatBeanUtil.getSeatId(variable.name)?.let {
            setUpdateDateSeat(it, liveInfo)
        }
    }

    override fun userCountChange(count: Int) {
        mLastUserCount = count
    }

    override fun publicMessage(message: SendLiveMessage) {
        if (message.type in ImLiveManager.publicTypes && message.businessId == mLiveInfo.liveId) {
            mMessageList.add(0, message)
            if (mMessageList.size >= AbstractLiveMessageView.CHAT_MAX_NUMBER) {
                (0 until AbstractLiveMessageView.CHAT_SINGLE_DELETE_COUNT).forEach { _ ->
                    mMessageList.removeAt(mMessageList.size - 1)
                }
            }
        }
        //其他消息处理
        when (message.type) {
            LIVE_KICK_ROOM -> { //踢出房间
                ToastGravity.showGravity(message.content)
                FloatingWindowManager.onDestroyed(mLiveInfo.type, mLiveInfo.roomId)
            }

            LIVE_MAGIC_LAMP_OPEN -> { //神灯开奖
                val payload = message.payload as MagicLampCountDownBean
                if (nowMagicLampCountDownBean == null) {
                    nowMagicLampCountDownBean = payload
                    magicLampLoading(payload)
                } else {
                    mWaitingList.add(payload)
                }
            }
        }
    }

    private fun magicLampLoading(data: MagicLampCountDownBean) {
        val context = ViewUtils.getAliveTopActivity()
        if (context == null || context !is BaseVmActivity<*>) return
        val lotteryTime = data.lotteryTime
        val serverTime = CacheUtil.getServerTime()
        var time = lotteryTime - serverTime

        if (time < 0) { //领取时间超过当前时间直接领取
            magicAward(context, data)
            magicNext()
            return
        }
        if (time > ANIMATION_MAX_TIME) {
            time = ANIMATION_MAX_TIME
        }
        magicJob = CoroutineScopeManager.ioScope.launch {
            try {
                delay(time)
                withContext(CoroutineScopeManager.mainDispatcher) {
                    magicAward(context, data)
                }
            } finally {
                if (coroutineContext[Job] == magicJob) {
                    magicJob = null
                }
            }
        }
    }

    private fun magicAward(context: BaseVmActivity<*>, data: MagicLampCountDownBean) {
        context.mViewModel.request({
            payerService.getLampLottery(mLiveInfo.userId, data.index.toLong())
        }, {
            magicNext()
        })
    }

    private fun magicNext() {
        nowMagicLampCountDownBean = null
        mWaitingList.poll()?.let {
            nowMagicLampCountDownBean = it
            magicLampLoading(it)
        }
    }

    override fun liveEvent(command: String, argument: DataArgument) {
    }

    override fun floatingMessage(message: SendLiveFloatingMessage) {
    }

    override fun getLifecycle(): Lifecycle = mLifecycleRegistry

    fun setUpdateDateSeat(seatId: Int, mLiveInfo: LiveRoomInfo) {
        //更新座位数据
        mSeatList[seatId].apply {
            val userJson = SeatBeanUtil.getUserJson(mLiveInfo, seatId)
            if (userJson != userData) { //两个数据不相等再设置
                userData = userJson
                if (!userJson.isNullOrEmpty()) {
                    userBasicVo = JsonUtils.fromJson(userJson, UserBasicVo::class.java)
                }
            }
            val mSiteLock = SeatBeanUtil.getLock(mLiveInfo, seatId) ?: false
            siteLock = mSiteLock
            siteMicStatus = SeatBeanUtil.getMicStatus(mLiveInfo, seatId)
            siteGainCoin = SeatBeanUtil.getGainCoin(mLiveInfo, seatId)
            siteStreamId = SeatBeanUtil.getStreamId(mLiveInfo, seatId)
        }
        inspectMaishangZego()
    }

    /**
     * 判断是否需要拉流
     */
    private fun handStream(seatId: Int, seatBean: SeatBean) {
        if (seatBean.userBasicVo == null || //没人不拉流
            seatBean.siteStreamId == null ||//没有流Id
            seatBean.siteLock == true || //被锁不拉流
            seatBean.siteMicStatus != 1   //关闭了麦克风
        ) {
            mPartyStreamProxy.closeStreamsBySeatId(seatId)
            return
        }
        if (seatBean.userBasicVo?.userId == UserManager.getUserId()) {//自己不拉流
            mPartyStreamProxy.closeStreamsBySeatId(seatId)
            return
        }
        seatBean.siteStreamId?.let {//没有流Id
            mPartyStreamProxy.openStream(seatId, it)
        }
    }

    /**
     * 获取自己座位信息
     */
    fun getOwnSeat(): SeatBean? {
        return mSeatList.find { it.userBasicVo?.userId == UserManager.getUserId() }
    }

    /**
     * 检查麦上用户 推拉流
     */
    fun inspectMaishangZego() {
        var inSeat = false //自己在座位吗
        var meSeat: SeatBean? = null //自己数据
        mSeatList.forEachIndexed { seatId, seatBean ->
            handStream(seatId, seatBean)
            if (seatBean.userBasicVo?.userId == UserManager.getUserId()) {
                inSeat = true
                val nowMicStatus = seatBean.siteMicStatus
                meSeat = seatBean
                PartyUserStateUtil.siteMicStatus = nowMicStatus
                PartyUserStateUtil.inTheMaiSeat = true
            }
        }

        if (!inSeat) { //自己没上麦
            PartyUserStateUtil.inTheMaiSeat = false
            PartyUserStateUtil.siteMicStatus = null
            mPartyStreamProxy.stopPublishStream()
            MediaProxy.closeMusic()
        } else {
            meSeat?.let { bean ->
                if (bean.siteMicStatus == 1) { //开了声音
                    if (bean.siteLock != true) {
                        bean.siteStreamId?.let { streamId ->
                            mPartyStreamProxy.publishStream(streamId)
                        }
                    }
                } else {
                    mPartyStreamProxy.stopPublishStream()
                }
            }
        }
    }

    //直播心跳
    private var mLiveHeartbeatJob: Job? = null
    private fun launchLiveHeartbeat(liveId: Long) {
        mLiveHeartbeatJob = CoroutineScopeManager.ioScope.launch {
            try {
                while (isActive) {
                    val resp = liveService.liveCheck(LiveIdBean(liveId))
                    if (resp.code == HTTP_SUCCESS_CODE) {
                        0
                    } else {
                        if (resp.code == CommonConst.ErrorCode.LIVE_NOT_EXIST) {
                            Int.MAX_VALUE
                        } else {

                        }
                    }
                    liveService.liveConsumeV2(liveId)
                    delay(LiveConst.HEARTBEAT_TIME)
                }
            } finally {
                if (mLiveHeartbeatJob == coroutineContext[Job]) {
                    mLiveHeartbeatJob = null
                }
            }
        }
    }

    /**
     * 网络和长连接变化
     */
    fun network(isNetwork: Boolean, isConnected: Boolean) {
        if (mIsDestroyed) {
            return
        }
        if (isConnected) {
            if (mIsAnchor) {
                recoverAnchorLive(mLiveInfo.roomId)
            } else {
                val lastRoom = SmartFoxManager.getLiveRoom()
                //如果上次是断开连接，这次连接上了，需要重连
                if (lastRoom == null) {
                    recoverJoinLive(mLiveInfo.userId, mPassword, null, mLiveInfo.roomId)
                }
            }

        }
    }

    /**
     * 主播重连
     */
    private fun recoverAnchorLive(roomId: String? = null) {
        recoverJoinLiveJob?.cancel()
        recoverJoinLiveJob = null
        recoverJoinLiveJob = CoroutineScopeManager.ioScope.launch {
            try {
                //这里立即重试一次
                withRetryNow {
                    SmartFoxQueueManager.sendLiveMessage(COMMAND_LIVE_RECOVER, LiveMsgIdMessage(roomId))
                }
            } catch (t: Throwable) {
                //恢复直播间失败，退出
                FloatingWindowManager.onDestroyed(mLiveInfo.type, mLiveInfo.roomId)
            }
        }
    }

    private var recoverJoinLiveJob: Job? = null

    /**
     * 观众重连
     */
    private fun recoverJoinLive(anchorId: Long, password: String? = null, delay: Long? = null, roomId: String? = null) {
        recoverJoinLiveJob?.cancel()
        recoverJoinLiveJob = null
        recoverJoinLiveJob = CoroutineScopeManager.ioScope.launch {
            if (delay != null && delay > 0) {
                delay(delay)
            }
            val data = StartLiveProxy.launchLiveMessageState(anchorId, {
                SmartFoxQueueManager.sendLiveMessage(
                    COMMAND_LIVE_JOIN,
                    LiveJoinMessage(anchorId = anchorId, password = password, roomId = roomId)
                )
            }, {
                val room = getRoom()
                room?.parseLiveInfo()?.let { variable ->
                    LiveInitInfo(variable, room.userCount)
                }
            })

            withContext(CoroutineScopeManager.mainDispatcher) {
                if (data is ResultState.Error) {
                    retryJoinLive()
                }
            }

        }

    }

    /**
     * 重连一下
     */
    private fun retryJoinLive() {
        //直播im是连接的，但是重新加入直播间失败，延迟1秒重试
        if (SmartFoxManager.isLiveConnected()) {
            recoverJoinLive(mLiveInfo.userId, mPassword, 2000, mLiveInfo.roomId)
        }
    }

    //主播退出直播间
    private fun exitLive(anchorId: Long, roomId: String? = null) {
        CoroutineScopeManager.ioScope.launch {
            val deferred = async {
                withContext(NonCancellable + CoroutineScopeManager.ioDispatcher) {
                    try {
                        SmartFoxQueueManager.sendLiveMessage(
                            COMMAND_LIVE_QUIT,
                            LiveQuitMessage(anchorId, roomId)
                        )
                    } catch (_: Throwable) {
                    }
                }
            }

            withTimeoutOrNull(1000) {
                deferred.await()
            }
        }
    }

    /**
     * 恢复到直播间
     * 目前只有 LiveConst.Type.PARTY_LIVE类型
     */
    fun recoverLive() {
        val topActivity = ViewUtils.getAliveTopActivity()
        val initInfo = LiveInitInfo(mLiveInfo, mLastUserCount, mScreenshotStrategy)
        if (mIsAnchor) {
            if (topActivity is BaseVbActivity<*, *>) {
                FloatingWindowManager.onDestroyed(mLiveInfo.type, mLiveInfo.roomId)
                when (mLiveInfo.type) {
                    LiveConst.Type.PARTY_LIVE -> {
                        Router.instance.setPath(RoutePath.PARTY_ANCHOR_ACTIVITY)
                            .withAny(LiveConst.Params.LIVE_INIT_INFO, initInfo)
                            .navigation()
                    }

                    LiveConst.Type.PARTY_GAME_LIVE -> {
                        Router.instance.setPath(RoutePath.PARTY_GAME_ANCHOR_ACTIVITY)
                            .withAny(LiveConst.Params.LIVE_INIT_INFO, initInfo)
                            .navigation()
                    }

                    LiveConst.Type.VIDEO_PARTY -> {
                        Router.instance.setPath(RoutePath.PARTY_VIDEO_ANCHOR_ACTIVITY)
                            .withAny(LiveConst.Params.LIVE_INIT_INFO, initInfo)
                            .navigation()
                    }

                    else -> {
                        Router.instance.setPath(RoutePath.LIVE_VIDEO_ACTIVITY)
                            .withAny(LiveConst.Params.LIVE_INIT_INFO, initInfo)
                            .navigation()
                    }
                }
            }
        } else {
            when (mLiveInfo.type) {
                LiveConst.Type.LIVE_AND_MATCH, LiveConst.Type.ONLY_LIVE, LiveConst.Type.ONLY_MATCH -> { //直播
                    topActivity?.let {
                        LiveUtils.toSpectator(mLiveInfo.userId).navigation(it)
                    }
                }

                LiveConst.Type.PARTY_LIVE -> {
                    Router.instance.setPath(RoutePath.PARTY_SPECTATOR_ACTIVITY)
                        .withInt(LiveConst.Params.LIVETYPE, LiveConst.Type.PARTY_LIVE)
                        .withLong(LiveConst.Params.ANCHORID, mLiveInfo.userId)
                        .withString(LiveConst.Params.ROOMID, mLiveInfo.roomId ?: "")
                        .withAny(LiveConst.Params.LIVEINITINFO, initInfo)
                        .navigation(topActivity)
                }

                LiveConst.Type.VIDEO_PARTY -> {
                    Router.instance.setPath(RoutePath.PARTY_SPECTATOR_ACTIVITY)
                        .withInt(LiveConst.Params.LIVETYPE, LiveConst.Type.VIDEO_PARTY)
                        .withLong(LiveConst.Params.ANCHORID, mLiveInfo.userId)
                        .withString(LiveConst.Params.ROOMID, mLiveInfo.roomId ?: "")
                        .withAny(LiveConst.Params.LIVEINITINFO, initInfo)
                        .navigation(topActivity)
                }

                LiveConst.Type.PARTY_GAME_LIVE -> {
                    Router.instance.setPath(RoutePath.PARTY_GAME_SPECTATOR_ACTIVITY)
                        .withLong(LiveConst.Params.ANCHORID, mLiveInfo.userId)
                        .withString(LiveConst.Params.ROOMID, mLiveInfo.roomId ?: "")
                        .withAny(LiveConst.Params.LIVEINITINFO, initInfo)
                        .navigation(topActivity)
                }

                else -> {
                    ToastGravity.showGravity(R.string.version_does_not_support)
                }
            }
        }
    }

    fun onDestroyed(
        liveType: Int?,
        roomId: String? = null,
    ) {
        mIsDestroyed = true
        NetworkUtils.unregisterNetworkStatusChangedListener(this)
        EventBus.getDefault().unregister(this)
        if (mIsAnchor) {
            PartyUserStateUtil.inTheMaiSeat = false
            PartyUserStateUtil.siteMicStatus = null
            LiveStateManager.changeState(LiveConst.State.NONE)
        } else {
            //观众进入直播状态
            LiveStateManager.updateSpectateState(false)
            PartyUserStateUtil.inTheMaiSeat = false
            PartyUserStateUtil.siteMicStatus = null
        }
        if (liveType != mLiveInfo.type || roomId != mLiveInfo.roomId) { //类型不匹配调用退出房间接口
            ToastGravity.showGravity(R.string.minimize_tips)
            exitLive(mLiveInfo.userId, mLiveInfo.roomId)
            MediaProxy.destroy()
            mPartyStreamProxy.destroyStreams()
        } else { //恢复到上一个直播间,保存临时数据
            if (liveType == LiveConst.Type.PARTY_LIVE) { //目前只有语音派对保存

                val tempList = mWaitingList.toMutableList()
                if (nowMagicLampCountDownBean != null || tempList.isNotEmpty()) {
                    if (nowMagicLampCountDownBean != null) {
                        tempList.add(0, nowMagicLampCountDownBean)
                    }
                    CommonCache.setMagicLampList(tempList)
                }

                mLiveInfo.roomId?.let { id ->
                    FloatingWindowManager.putMessage(id, mPartyStreamProxy, mMessageList)
                }
            }
        }
        mLiveHeartbeatJob?.cancel()
        mLiveHeartbeatJob = null
        recoverJoinLiveJob?.cancel()
        recoverJoinLiveJob = null
        magicJob?.cancel()
        magicJob = null

        if (mLifecycleRegistry.currentState == Lifecycle.State.STARTED) {
            setCurrentState(Lifecycle.State.RESUMED)
            setCurrentState(Lifecycle.State.DESTROYED)
        }
        mPartyImProxy = null
    }

    private fun stopStream() {
        if (mLifecycleRegistry.currentState == Lifecycle.State.STARTED) {
            setCurrentState(Lifecycle.State.RESUMED)
            setCurrentState(Lifecycle.State.DESTROYED)
        }
        mPartyStreamProxy.destroyStreams()
        mPartyImProxy = null
    }

    /**
     * =====================网络==============================
     */
    override fun onDisconnected() {
        network(true, SmartFoxManager.isLiveConnected())
    }

    override fun onConnected(networkType: NetworkUtils.NetworkType?) {
        network(false, SmartFoxManager.isLiveConnected())
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onImConnected(event: ImConnectedEvent) {
        if (event.type == SmartFoxConnector.CLIENT_LIVE) {
            network(NetworkUtils.isConnected(), true)
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onImDisconnected(event: ImDisconnectedEvent) {
        if (event.type == SmartFoxConnector.CLIENT_LIVE) {
            network(NetworkUtils.isConnected(), false)
        }
    }
}